package puzzle.slilin2.solver;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import puzzle.common.data.HatanException;
import puzzle.common.point.Direction;
import puzzle.common.point.Pnt;
import puzzle.common.solver.TopologicalRule;
import puzzle.common.solver.Track;
import puzzle.common.solver.TrackTopology;
import puzzle.common.solver.topology.ClosureAnalyzable;
import puzzle.common.solver.topology.ClosureAnalyzer;
import puzzle.slilin2.data.SlilinBoard;
import tomoto.util.IntHolder;

class ClosureTopologicalRule implements TopologicalRule<SlilinBoard, TrackTopology> {

	public boolean apply(SlilinBoard b, TrackTopology topology) throws HatanException {
		List<Track> tracks = topology.getTracks();

		ClosureAnalyzer z = new ClosureAnalyzer(new SlilinClosureAnalyzable(b));

		Map<Integer, IntHolder> endPointCountMap = new HashMap<Integer, IntHolder>();
		for (Track track : tracks) {
			incrementEndPointCount(z, endPointCountMap, track.getEnds().car);
			incrementEndPointCount(z, endPointCountMap, track.getEnds().cdr);
		}

		for (IntHolder endPointCount : endPointCountMap.values()) {
			if (endPointCount.value % 2 != 0) {
				throw new HatanException();
			}
		}
		return false;
	}

	private void incrementEndPointCount(ClosureAnalyzer z, Map<Integer, IntHolder> map, Pnt p) {
		int n = z.getClosureNumber((p.x - 1) / 2, (p.y - 1) / 2);
		IntHolder count = map.get(n);
		if (count == null) {
			count = new IntHolder();
			map.put(n, count);
		}
		count.value++;
	}

	private static class SlilinClosureAnalyzable implements ClosureAnalyzable {
		private SlilinBoard m_board;

		public SlilinClosureAnalyzable(SlilinBoard b) {
			m_board = b;
		}

		public int getWidth() {
			return m_board.getLogicalWidth() + 1;
		}

		public int getHeight() {
			return m_board.getLogicalHeight() + 1;
		}

		public boolean isConnected(int x, int y, Direction d) {
			return !m_board.getLineCellState(x * 2 + 1 + d.v.dx, y * 2 + 1 + d.v.dy).isFixed();
		}

		public boolean isClosureMember(int x, int y) {
			return true;
		}

	}

}
